home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ham Radio 2000 #2
/
Ham Radio 2000 - Volume 2.iso
/
HAMV2
/
TCP_IP
/
TNOS230S
/
HOP.C
< prev
next >
Wrap
C/C++ Source or Header
|
1997-08-18
|
11KB
|
412 lines
/*
* HOP.C -- trace route packets take to a remote host
*
* 02-90 -- Katie Stevens (dkstevens@ucdavis.edu)
* UC Davis, Computing Services
* Davis, CA
* 04-90 -- Modified by Phil Karn to use raw IP sockets to read replies
* 08-90 -- Modified by Bill Simpson to display domain names
*
* Mods by PA0GRI (newsession param)
*/
#include "global.h"
#include "commands.h"
#include "mbuf.h"
#include "usock.h"
#include "session.h"
#include "domain.h"
#include "icmp.h"
#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: hop.c,v 1.20 1997/08/19 01:19:22 root Exp root $";
#endif
#define HOPMAXQUERY 5 /* Max# queries each TTL value */
static int16 Hoprport = 32768 + 666; /* funny port for udp probes */
#if 0 /* not used */
#define HOP_HIGHBIT 32768 /* Mask to check ICMP msgs */
#endif
#define HOPTRACE 1 /* Enable HOP tracing */
#ifdef HOPTRACE
static int Hoptrace = 0;
static int hoptrace (int argc, char *argv[], void *p);
#endif
static unsigned short Hopmaxttl = 30; /* max attempts */
static unsigned short Hopmaxwait = 5; /* secs timeout each attempt */
static unsigned short Hopquery = 3; /* #probes each attempt */
static int hopcheck (int argc, char *argv[], void *p);
static int hopttl (int argc, char *argv[], void *p);
static int hopwait (int argc, char *argv[], void *p);
static int hopnum (int argc, char *argv[], void *p);
static int geticmp (int s, int16 lport, int16 fport,
uint32 * sender, char *type, char *code);
static struct cmds Hopcmds[] =
{
{ "check", hopcheck, 2048, 2, "check [-n] <host>" },
{ "maxttl", hopttl, 0, 0, NULLCHAR },
{ "maxwait", hopwait, 0, 0, NULLCHAR },
{ "queries", hopnum, 0, 0, NULLCHAR },
#ifdef HOPTRACE
{ "trace", hoptrace, 0, 0, NULLCHAR },
#endif
{ NULLCHAR, 0, 0, 0, NULLCHAR }
};
/* attempt to trace route to a remote host */
int
dohop (int argc, char *argv[], void *p)
{
return subcmd (Hopcmds, argc, argv, p);
}
/* Set/show # queries sent each TTL value */
static int
hopnum (int argc, char *argv[], void *p OPTIONAL)
{
int r;
int16 x = Hopquery;
r = setshort (&x, "# queries each attempt", argc, argv);
if ((((short) x) <= 0) || (x > HOPMAXQUERY)) {
tprintf ("Must be 0 < x <= %d\n", HOPMAXQUERY);
return 0;
} else
Hopquery = x;
return r;
}
#ifdef HOPTRACE
/* Set/show tracelevel */
static int
hoptrace (int argc, char *argv[], void *p OPTIONAL)
{
return setbool (&Hoptrace, "HOPCHECK tracing", argc, argv);
}
#endif
/* Set/show maximum TTL value for a hopcheck query */
static int
hopttl (int argc, char *argv[], void *p OPTIONAL)
{
int r;
int16 x = Hopmaxttl;
r = setshort (&x, "Max attempts to reach host", argc, argv);
if ((((short) x) <= 0) || (x > 255)) {
tputs ("Must be 0 < x <= 255\n");
return 0;
} else
Hopmaxttl = x;
return r;
}
/* Set/show #secs until timeout for a hopcheck query */
static int
hopwait (int argc, char *argv[], void *p OPTIONAL)
{
int r;
int16 x = Hopmaxwait;
r = setshort (&x, "# secs to wait for reply to query", argc, argv);
if (((short) x) <= 0) {
tputs ("Must be >= 0\n");
return 0;
} else
Hopmaxwait = x;
return r;
}
/* send probes to trace route of a remote host */
static int
hopcheck (int argc, char *argv[], void *p OPTIONAL)
{
struct session *sp; /* Session for trace output */
int s; /* Socket for queries */
int s1; /* Raw socket for replies */
struct socket lsocket; /* Local socket sending queries */
struct socket rsocket; /* Final destination of queries */
int32 cticks; /* Timer for query replies */
uint32 icsource = 0; /* Sender of last ICMP reply */
char ictype = 0; /* ICMP type last ICMP reply */
char iccode = 0; /* ICMP code last ICMP reply */
uint32 lastaddr; /* Sender of previous ICMP reply */
struct sockaddr_in sock;
register struct usock *usp;
register struct sockaddr_in *sinp;
unsigned char sndttl, q;
int tracedone = 0;
int ilookup = 1; /* Control of inverse domain lookup */
char *hostname;
int trans; /* Save IP address translation state */
int save_trace;
int useind = 1;
#ifdef g1emmx
char *sname; /* Used in resolve_a() call */
#endif
/*Make sure this comes from console - WG7J*/
if (Curproc->input != Command->input)
return 0;
if (!strcasecmp (argv[1], "-n")) {
ilookup = 0;
useind = 2;
if (argc < 3) {
tprintf ("Usage: hop check [-n] <host>");
return 1;
}
}
hostname = argv[useind];
/* Allocate a session descriptor */
if ((sp = newsession (hostname, HOP, 0)) == NULLSESSION) {
tputs (TooManySessions);
(void) keywait (NULLCHAR, 1);
return 1;
}
sp->s = s = -1;
sp->flowmode = 1;
/* Setup UDP socket to remote host */
sock.sin_family = AF_INET;
sock.sin_port = Hoprport;
tprintf ("Resolving %s... ", hostname);
if ((sock.sin_addr.s_addr = resolve (hostname)) == 0) {
tprintf (Badhost, hostname);
(void) keywait (NULLCHAR, 1);
freesession (sp);
return 1;
}
/* Open socket to remote host */
tprintf ("hopcheck to %s\n", psocket ((void *) &sock));
if ((sp->s = s = socket (AF_INET, SOCK_DGRAM, 0)) == -1) {
tputs (Nosock);
(void) keywait (NULLCHAR, 1);
freesession (sp);
return 1;
}
if (connect (s, (char *) &sock, sizeof (sock)) == -1) {
tputs ("Connect failed\n");
(void) keywait (NULLCHAR, 1);
freesession (sp);
return 1;
}
if ((s1 = socket (AF_INET, SOCK_RAW, ICMP_PTCL)) == -1) {
tputs (Nosock);
(void) keywait (NULLCHAR, 1);
freesession (sp);
return 1;
}
/* turn off icmp tracing while hop-checking */
save_trace = Icmp_trace;
Icmp_trace = 0;
/* Setup structures to send queries */
/* Retrieve socket details for user socket control block */
usp = itop (s);
sinp = (struct sockaddr_in *) usp->name;
lsocket.address = sinp->sin_addr.s_addr;
lsocket.port = sinp->sin_port;
sinp = (struct sockaddr_in *) usp->peername;
rsocket.address = sinp->sin_addr.s_addr;
/* Send queries with increasing TTL; start with TTL=1 */
if (Hoptrace)
log (sp->s, "HOPCHECK start trace to %s\n", sp->name);
for (sndttl = 1; (sndttl < Hopmaxttl); ++sndttl, sinp->sin_port++) {
/* Increment funny UDP port number each round */
rsocket.port = sinp->sin_port;
tprintf ("%3d:", sndttl);
lastaddr = (int32) 0;
/* Send a round of queries */
for (q = 0; (q < Hopquery); ++q) {
(void) send_udp (&lsocket, &rsocket, 0, (char) sndttl, NULLBUF, 0, 0, 0);
cticks = msclock ();
kalarm (((long) Hopmaxwait) * 1000L);
/* Wait for a reply to our query */
if (geticmp (s1, lsocket.port, rsocket.port, &icsource, &ictype, &iccode) == -1) {
if (errno != EALARM) {
kalarm (0L); /* cancel alarm */
goto done; /* User reset */
}
/* Alarm rang, give up waiting for replies */
tputs (" ***");
continue;
}
/* Save #ticks taken for reply */
cticks = msclock () - cticks;
/* Report ICMP reply */
if (icsource != lastaddr) {
struct rr *save_rrlp, *rrlp;
if (lastaddr != (int32) 0)
tputs ("\n ");
/* Save IP address translation state */
trans = DTranslate;
/* Force output to be numeric IP addr */
DTranslate = 0;
tprintf (" %-15s", inet_ntoa (icsource));
/* Restore original state */
DTranslate = trans;
#ifdef g1emmx
if ((sname = resolve_a (icsource, FALSE)) != NULLCHAR) {
tprintf (" %s", sname);
free (sname);
}
#else
if (ilookup) {
for (rrlp = save_rrlp = inverse_a (icsource);
rrlp != NULLRR;
rrlp = rrlp->next) {
if (rrlp->rdlength > 0) {
switch (rrlp->type) {
case TYPE_PTR:
tprintf (" %s", rrlp->rdata.name);
break;
case TYPE_A:
tprintf (" %s", rrlp->name);
break;
default:
break;
}
if (rrlp->next != NULLRR)
tprintf ("\n%20s", " ");
}
}
free_rr (save_rrlp);
#endif
}
lastaddr = icsource;
}
tprintf (" (%ld ms)", cticks);
#ifdef HOPTRACE
if (Hoptrace)
log (sp->s, "(hopcheck) ICMP from %s (%ldms) %s %s",
inet_ntoa (icsource), cticks, Icmptypes[(int) ictype],
((ictype == ICMP_TIME_EXCEED) ? Exceed[(int) iccode] : Unreach[(int) iccode]));
#endif
/* Check type of reply */
if (ictype == ICMP_TIME_EXCEED)
continue;
/* Reply was: destination unreachable */
switch (iccode) {
case ICMP_PORT_UNREACH: ++tracedone;
break;
case ICMP_NET_UNREACH: ++tracedone;
tputs (" !N");
break;
case ICMP_HOST_UNREACH: ++tracedone;
tputs (" !H");
break;
case ICMP_PROT_UNREACH: ++tracedone;
tputs (" !P");
break;
case ICMP_FRAG_NEEDED: ++tracedone;
tputs (" !F");
break;
case ICMP_ROUTE_FAIL: ++tracedone;
tputs (" !S");
break;
case ICMP_ADMIN_PROHIB: ++tracedone;
tputs (" !A");
break;
default: tputs (" !?");
break;
}
}
/* Done with this round of queries */
kalarm (0L);
tputc ('\n');
/* Check if we reached remote host this round */
if (tracedone != 0)
break;
}
/* Done with hopcheck */
done: close_s (s);
sp->s = -1;
close_s (s1);
tputs ("hopcheck done: ");
Icmp_trace = save_trace;
if (sndttl >= Hopmaxttl)
tputs ("!! maximum TTL exceeded\n");
else if ((icsource == rsocket.address) && (iccode == ICMP_PORT_UNREACH))
tprintf ("normal (%s %s)\n", Icmptypes[(int) ictype], Unreach[(int) iccode]);
else
tprintf ("!! %s %s\n", Icmptypes[(int) ictype], Unreach[(int) iccode]);
#ifdef HOPTRACE
if (Hoptrace)
log (sp->s, "HOPCHECK to %s done", sp->name);
#endif
(void) keywait (NULLCHAR, 1);
freesession (sp);
return 0;
}
/* Read raw network socket looking for ICMP messages in response to our
* UDP probes
*/
static int
geticmp (int s, int16 lport, int16 fport, uint32 *sender, char *type, char *code)
{
int size;
struct icmp icmphdr;
struct ip iphdr;
struct udp udphdr;
struct mbuf *bp;
struct sockaddr_in sock;
for ( ; ; ) {
size = sizeof (sock);
if (recv_mbuf (s, &bp, 0, (char *) &sock, &size) == -1)
return -1;
/* It's an ICMP message, let's see if it's interesting */
(void) ntohicmp (&icmphdr, &bp);
if ((icmphdr.type != ICMP_TIME_EXCEED ||
icmphdr.code != ICMP_TTL_EXCEED)
&& icmphdr.type != ICMP_DEST_UNREACH) {
/* We're not interested in these */
free_p (bp);
continue;
}
(void) ntohip (&iphdr, &bp);
if (iphdr.protocol != UDP_PTCL) {
/* Not UDP, so can't be interesting */
free_p (bp);
continue;
}
(void) ntohudp (&udphdr, &bp);
if (udphdr.dest != fport || udphdr.source != lport) {
/* Not from our hopcheck session */
free_p (bp);
continue;
}
/* Passed all of our checks, so return it */
*sender = sock.sin_addr.s_addr;
*type = icmphdr.type;
*code = icmphdr.code;
free_p (bp);
return 0;
}
}